import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import seaborn as sns

# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# 1. 数据加载和预处理
# 读取Excel数据
data = pd.read_excel('主成分分析-2.xlsx')

# 提取特征列和城市名称
features = data.iloc[:, 1:5].values  # 提取特征矩阵
cities = data.iloc[:, 0].values      # 提取城市名称

# 2. 数据标准化
# 使用StandardScaler进行标准化，将数据转换为均值为0，方差为1的标准正态分布
scaler = StandardScaler()
features_scaled = scaler.fit_transform(features)

# 3. PCA分析
# 初始化PCA对象，不限制主成分数量
pca = PCA()
features_pca = pca.fit_transform(features_scaled)

# 4. 计算各主成分的方差贡献率和累计贡献率
variance_ratio = pca.explained_variance_ratio_
cumulative_ratio = np.cumsum(variance_ratio)

# 确定需要保留的主成分数量（累计贡献率达到68%）
n_components = np.where(cumulative_ratio >= 0.68)[0][0] + 1
print(f"\n需要保留的主成分数量：{n_components}（累计贡献率≥68%）")
print("解释：这表示我们只需要使用前{}个主成分，就可以保留原始数据68%以上的信息量，实现了数据的降维简化。".format(n_components))

# 使用确定的主成分数量重新进行PCA
pca = PCA(n_components=n_components)
features_pca = pca.fit_transform(features_scaled)

# 打印每个主成分的方差贡献率及其意义
print("\n各主成分的方差贡献率及其意义：")
print("方差贡献率表示每个主成分对原始数据变异性的解释程度，越大表示这个主成分越重要")
for i, ratio in enumerate(pca.explained_variance_ratio_):
    print(f"主成分 {i+1}: {ratio:.4f} ({ratio*100:.2f}%)")

print("\n累计方差贡献率及其意义：")
print("累计方差贡献率表示到当前主成分为止，总共能解释原始数据多少百分比的信息量")
cumulative_ratio = np.cumsum(pca.explained_variance_ratio_)
for i, ratio in enumerate(cumulative_ratio):
    print(f"前 {i+1} 个主成分: {ratio:.4f} ({ratio*100:.2f}%)")

# 5. 获取载荷矩阵（主成分与原始变量的相关系数）
loadings = pca.components_.T * np.sqrt(pca.explained_variance_)
loadings_df = pd.DataFrame(
    loadings,
    columns=[f'PC{i+1}' for i in range(loadings.shape[1])],
    index=['Feature1', 'Feature2', 'Feature3', 'Feature4']
)

print("\n载荷矩阵及其意义：")
print("载荷矩阵显示了原始变量与主成分之间的相关性，数值越大（绝对值）表示该原始变量对主成分的贡献越大")
print(loadings_df)

# 6. 计算并排序第一主成分得分
pc1_scores = pd.DataFrame({
    '城市': cities,
    'PC1得分': features_pca[:, 0]
})
pc1_scores_sorted = pc1_scores.sort_values('PC1得分', ascending=False)

print("\n城市按第一主成分得分排序及其意义：")
print("第一主成分得分代表城市的综合表现，得分越高说明该城市在主要评价维度上的综合表现越好")
print("具体来说：")
print("1. 得分最高的城市在主要评价指标上（特别是对第一主成分贡献最大的指标）表现最好")
print("2. 得分最低的城市在这些指标上的表现相对较差")
print("3. 得分的差异反映了城市间发展的不平衡性")
print(pc1_scores_sorted)

# 7. 绘制前两个主成分的散点图
plt.figure(figsize=(10, 8))
plt.scatter(features_pca[:, 0], features_pca[:, 1])

# 添加城市标签
for i, city in enumerate(cities):
    plt.annotate(city, (features_pca[i, 0], features_pca[i, 1]))

plt.xlabel('第一主成分（反映城市综合实力）')
plt.ylabel('第二主成分（反映城市发展特色）')
plt.title('城市PCA主成分散点图\n展示城市在两个主要维度上的分布情况')
plt.grid(True)
plt.show()

# 8. 保存结果到Excel
results = pd.DataFrame({
    '城市': cities,
    'PC1': features_pca[:, 0],
    'PC2': features_pca[:, 1]
})
results.to_excel('pca_results.xlsx', index=False) 